/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.simba.controller;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.TreeSet;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import org.simba.NER.NerTool;
import org.simba.NER.NerToolFactory;
import org.simba.apriori.AprioriFunction;
import org.simba.apriori.AprioriFunctionFactory;
import org.simba.coherence.CoherenceFunction;
import org.simba.coherence.CoherenceFunctionFactory;
import org.simba.coherence.CoherenceMatrix;
import org.simba.disambiguation.AlgorithmFactory;
import org.simba.similarity.SimilarityFunction;
import org.simba.similarity.SimilarityFunctionFactory;
import org.simba.utils.Configuration;
import org.simba.utils.EntityUriMap;
import org.simba.utils.NamedEntity;

/**
 * Implements a generic disambiguation controller. Simply makes clear how the parts
 * interact. The server version should
 * - Rely on indexed label data to ensure improved runtimes
 * - A priori score data could also be precomputed
 * @author ngonga
 */
public class GenericController {

    static Logger logger = Logger.getLogger("AEON");

    /** Runs the named entity disambiguation
     * @param config Contains all the information necessary to carry out a NED task, incl.
     * inputText Text in which the entities are contained
     * nerTool Name of the NER tool to be used
     * similarity Similarity function to be used
     * coherence Coherence function to be used
     * apriori A-priori function to be used
     * algorithm Algorithm to utilized
     * sparqlEndpoint Endpoint of the knowledge base to utilize
     * graph Graph in the knowledge baed
     * labelProperties Name of properties used for labeling (rdfs:label, 
     * dc:title, etc.)
     * @return A mapping of named entities and URIs including scores
     */
    public static EntityUriMap run(Configuration config) {

        logger.info("1. Getting Named Entities");
        //1. get NEs
        NerTool ner = NerToolFactory.get(config.nerTool);
        TreeSet<NamedEntity> namedEntities = ner.getNEs(config.inputText);
        logger.info("Got entities " + namedEntities);
        if (namedEntities.isEmpty()) {
            return null;
        }

        logger.info("2. Getting candidates URIs");
        //2. Get all mapping uris including their similarity to the named entities
        SimilarityFunction simFunction = SimilarityFunctionFactory.get(config.similarity);

        EntityUriMap mappingUriSet = simFunction.getMappings(config, namedEntities);

        logger.info("Got following URIs: " + mappingUriSet);

        logger.info("3. Getting a-priori score for candidate URIs");
        //3. Get apriori score
        AprioriFunction aprioriFunction = AprioriFunctionFactory.get(config.apriori);
        HashMap<String, Double> aprioriScores;
        if (config.algorithm.startsWith("weighted") || config.algorithm.startsWith("norma")
                || config.algorithm.startsWith("linear") || config.algorithm.startsWith("aprio")) {
            aprioriScores = aprioriFunction.getAprioriScore(mappingUriSet.getAllUris(), config);
        } else {
            aprioriScores = null;
        }
        logger.info("Got the following a-priori scores: " + aprioriScores);
        //System.exit(1);
        logger.info("4. Computing coherence score for candidate URIs");
        //4. Get coherence matrix
        CoherenceFunction coherenceFunction = null;
        CoherenceMatrix coherenceMatrix = null;
        if (config.algorithm.startsWith("weighted") || config.algorithm.startsWith("norma")) {
            coherenceFunction = CoherenceFunctionFactory.get(config.coherence);
            coherenceMatrix = coherenceFunction.getCoherence(aprioriScores.keySet(),
                    config);
        }
        logger.info("Got the following coherence matrix: " + coherenceMatrix);
        logger.info("5. Running disambiguation algorithm");
        //5. Run algorithm and return results        
        EntityUriMap result = AlgorithmFactory.get(config.algorithm).getMapping(mappingUriSet,
                coherenceMatrix, aprioriScores, config);

//        HashMap<NamedEntity, String>  m1, m2, m3, m4, m5;
//        config.algorithm = "Similarity";
//        m1 = AlgorithmFactory.get(config.algorithm).getMapping(mappingUriSet,
//                coherenceMatrix, aprioriScores, config).getBestMapping();
//        config.algorithm = "Apriori";
//        m2 = AlgorithmFactory.get(config.algorithm).getMapping(mappingUriSet,
//                coherenceMatrix, aprioriScores, config).getBestMapping();
//        config.algorithm = "Linear";
//        m3 = AlgorithmFactory.get(config.algorithm).getMapping(mappingUriSet,
//                coherenceMatrix, aprioriScores, config).getBestMapping();
//        config.algorithm = "WeightedCoherence";
//        m4 = AlgorithmFactory.get(config.algorithm).getMapping(mappingUriSet,
//                coherenceMatrix, aprioriScores, config).getBestMapping();
//        config.algorithm = "NormalizedHits";
//        m5 = AlgorithmFactory.get(config.algorithm).getMapping(mappingUriSet,
//                coherenceMatrix, aprioriScores, config).getBestMapping();
//        
//        logger.info("Similarity -> "+m1);
//        logger.info("Apriori -> "+m2);
//        logger.info("Linear -> "+m3);
//        logger.info("WeightedCoherence -> "+m4);
//        logger.info("Hits -> "+m5);
//        //logger.info("Got the following result: "+result);

        return result;
    }

    public static void annotateCorpus(String input, String output, String algorithm) {
        Configuration config = new Configuration();
        config.algorithm = algorithm;
        config.apriori = "edgecount";
        config.coherence = "edgecount";
        config.graph = null;
        //config.inputText = "Former Brazilian president Itamar Franco dies aged 81.";
        config.labelProperties = new TreeSet<String>();
        config.nerTool = "fox";
        config.similarity = "trigrams";
        config.sparqlEndpoint = "http://live.dbpedia.org/sparql";

        HashMap<NamedEntity, String> results;
        try {
            PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(output)));
            BufferedReader rd = new BufferedReader(new FileReader(input));
            String line = rd.readLine();
            TreeSet<NamedEntity> nes;
            while (line != null) {
                //line = line.replaceAll(",", "");
                //line = line.replaceAll(";", "");
                config.inputText = line;
                results = run(config).getBestMapping();
                String copy = line + "";
                nes = new TreeSet<NamedEntity>();
                for (NamedEntity ne : results.keySet()) {
                    nes.add(ne);
                }

                //now rewrite string
                StringBuilder b = new StringBuilder(copy);
                System.out.println(nes);
                for (NamedEntity ne : nes) {
                    System.out.println(ne);
                    if (!copy.substring(0, ne.offset+ne.label.length()).contains("[")) {
                        copy = copy.substring(0, ne.offset) + "[" + ne.label + ", "
                                + ne.type + ", " + results.get(ne).replaceAll("http://dbpedia.org/resource/", "") + "]"
                                + copy.substring(ne.offset + ne.label.length());
                    }
                }
                writer.println(copy);
                writer.flush();
                line = rd.readLine();
            }
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
//        Configuration config = new Configuration();
//        config.algorithm = "linear";
//        config.apriori = "edgecount";
//        config.coherence = "edgecount";
//        config.graph = null;
//        config.inputText = "Former Brazilian president Itamar Franco dies aged 81.";
//        config.inputText = config.inputText.replaceAll(",", "");
//        config.inputText = config.inputText.replaceAll(";", "");
//        config.labelProperties = new TreeSet<String>(); //default
//        //config.labelProperties.add("<http://www.w3.org/2000/01/rdf-schema#label>");
//        //config.labelProperties.add("<http://dbpedia.org/ontology/abstract>");
//        config.nerTool = "fox";
//        config.similarity = "trigrams";
//        config.sparqlEndpoint = "http://live.dbpedia.org/sparql";
//
//        logger.info("Disambiguation results:\n" + run(config).getBestMapping());        
        annotateCorpus("D:/Work/Data/WWW_Corpus/corpus1.txt", "D:/Work/Data/WWW_Corpus/corpus_annotated_linear_0.3.1.txt", "linear");
    }
}
